﻿/*
* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* This software is provided 'as-is', without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

package Box2D.Dynamics.Contacts{


import Box2D.Collision.Shapes.*;
import Box2D.Collision.*;
import Box2D.Dynamics.*;
import Box2D.Common.*;
import Box2D.Common.Math.*;


public class b2PolyAndCircleContact extends b2Contact{
   
   static public function Create(shape1:b2Shape, shape2:b2Shape, allocator:*):b2Contact{
      return new b2PolyAndCircleContact(shape1, shape2);
   }
   static public function Destroy(contact:b2Contact, allocator:*): void{
   }

   public function b2PolyAndCircleContact(shape1:b2Shape, shape2:b2Shape){
      super(shape1, shape2);
      
      m_manifold = m_manifolds[0];
      
      b2Settings.b2Assert(m_shape1.m_type == b2Shape.e_polygonShape);
      b2Settings.b2Assert(m_shape2.m_type == b2Shape.e_circleShape);
      m_manifold.pointCount = 0;
      var point:b2ManifoldPoint = m_manifold.points[0];
      point.normalImpulse = 0.0;
      point.tangentImpulse = 0.0;
   }
   //~b2PolyAndCircleContact() {}

   //
   static private const s_evalCP:b2ContactPoint = new b2ContactPoint();
   //
   public override function Evaluate(listener:b2ContactListener): void{
      var i:int;
      var v1:b2Vec2;
      var v2:b2Vec2;
      var mp0:b2ManifoldPoint;
      
      var b1:b2Body = m_shape1.m_body;
      var b2:b2Body = m_shape2.m_body;
      
      //b2Manifold m0;
      //memcpy(&m0, &m_manifold, sizeof(b2Manifold));
      // TODO: make sure this is completely necessary
      m0.Set(m_manifold);
      
      b2Collision.b2CollidePolygonAndCircle(m_manifold, m_shape1 as b2PolygonShape, b1.m_xf, m_shape2 as b2CircleShape, b2.m_xf);
      
      var persisted:Array = [false, false];
      
      var cp:b2ContactPoint = s_evalCP;
      cp.shape1 = m_shape1;
      cp.shape2 = m_shape2;
      cp.friction = m_friction;
      cp.restitution = m_restitution;
      
      // Match contact ids to facilitate warm starting.
      if (m_manifold.pointCount > 0)
      {
         // Match old contact ids to new contact ids and copy the
         // stored impulses to warm start the solver.
         for (i = 0; i < m_manifold.pointCount; ++i)
         {
            var mp:b2ManifoldPoint = m_manifold.points[ i ];
            mp.normalImpulse = 0.0;
            mp.tangentImpulse = 0.0;
            var found:Boolean = false;
            var idKey:uint = mp.id._key;
   
            for (var j:int = 0; j < m0.pointCount; ++j)
            {
               if (persisted[j] == true)
               {
                  continue;
               }
   
               mp0 = m0.points[ j ];
   
               if (mp0.id._key == idKey)
               {
                  persisted[j] = true;
                  mp.normalImpulse = mp0.normalImpulse;
                  mp.tangentImpulse = mp0.tangentImpulse;
   
                  // A persistent point.
                  found = true;
   
                  // Report persistent point.
                  if (listener != null)
                  {
                     cp.position = b1.GetWorldPoint(mp.localPoint1);
                     v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1);
                     v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2);
                     cp.velocity.Set(v2.x - v1.x, v2.y - v1.y);
                     cp.normal.SetV(m_manifold.normal);
                     cp.separation = mp.separation;
                     cp.id.key = idKey;
                     listener.Persist(cp);
                  }
                  break;
               }
            }
   
            // Report added point.
            if (found == false && listener != null)
            {
               cp.position = b1.GetWorldPoint(mp.localPoint1);
               v1 = b1.GetLinearVelocityFromLocalPoint(mp.localPoint1);
               v2 = b2.GetLinearVelocityFromLocalPoint(mp.localPoint2);
               cp.velocity.Set(v2.x - v1.x, v2.y - v1.y);
               cp.normal.SetV(m_manifold.normal);
               cp.separation = mp.separation;
               cp.id.key = idKey;
               listener.Add(cp);
            }
         }
   
         m_manifoldCount = 1;
      }
      else
      {
         m_manifoldCount = 0;
      }
      
      if (listener == null)
      {
         return;
      }
      
      // Report removed points.
      for (i = 0; i < m0.pointCount; ++i)
      {
         if (persisted[i])
         {
            continue;
         }
         
         mp0 = m0.points[ i ];
         cp.position = b1.GetWorldPoint(mp0.localPoint1);
         v1 = b1.GetLinearVelocityFromLocalPoint(mp0.localPoint1);
         v2 = b2.GetLinearVelocityFromLocalPoint(mp0.localPoint2);
         cp.velocity.Set(v2.x - v1.x, v2.y - v1.y);
         cp.normal.SetV(m0.normal);
         cp.separation = mp0.separation;
         cp.id.key = mp0.id._key;
         listener.Remove(cp);
      }
   }
   
   public override function GetManifolds():Array
   {
      return m_manifolds;
   }

   private var m_manifolds:Array = [new b2Manifold()];
   public var m_manifold:b2Manifold;
   private var m0:b2Manifold = new b2Manifold();
   
}

}